package com.kt.common.coroutines

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

/*suspend fun main() {
    val time = measureTimeMillis {
        val one = doSomethingUsefulOne()
        val two = doSomethingUsefulTwo()
        println("The answer is ${one + two}")
    }
    println("Completed in $time ms")
}*/

suspend fun doSomethingUsefulOne(): Int {
    println("doSomethingUsefulOne")
    delay(2000L)
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    println("doSomethingUsefulTwo")
    delay(1000L)
    return 29
}

//async await  组合使用的时候能并发执行并且等待值都返回了再做加法
/*
fun main() = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}*/

/*
//设置async为惰性启动，在start 或者await的时候才会调用
fun main() = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
        val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
        // 执行一些计算
        one.start() // 启动第一个
        two.start() // 启动第二个
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}*/


/** async 风格的函数 */
fun doSomethingUsefulOneAsync() = GlobalScope.async {
    doSomethingUsefulOne()
}

fun doSomethingUsefulTwoAsync() = GlobalScope.async {
    doSomethingUsefulTwo()
}

/*fun main() {
    val time = measureTimeMillis {
        // 我们可以在协程外面启动异步执行
        val one = doSomethingUsefulOneAsync()
        val two = doSomethingUsefulTwoAsync()
        // 但是等待结果必须调用其它的挂起或者阻塞
        // 当我们等待结果的时候，这里我们使用 `runBlocking { …… }` 来阻塞主线程
        runBlocking {
            println("The answer is ${one.await() + two.await()}")
        }
    }
    println("Completed in $time ms")
}*/

/**async 结构化并发*/
/*
fun main() = runBlocking {
    val time = measureTimeMillis {
        println("The answer is ${conCurrentSum()}")
    }
    println("Completed in $time ms")
}

suspend fun conCurrentSum(): Int = coroutineScope {
    val one = async { doSomethingUsefulOne() }
    val two = async { doSomethingUsefulTwo() }
    one.await() + two.await()
}*/

suspend fun failedConcurrentSum(): Int = coroutineScope {
    val one = async <Int>{
        try {
            delay(Int.MAX_VALUE.toLong())
            42
        }finally {
            println("First child was cancelled")
        }
    }
    val two = async<Int> {
        println("Second child throws an exception")
        throw ArithmeticException()
    }

    one.await() + two.await()
}

fun main() = runBlocking<Unit> {
    try {
        failedConcurrentSum()
    } catch(e: ArithmeticException) {
        println("Computation failed with ArithmeticException")
    }
}